perm filename EFRPKT.C[11,HE] blob sn#688196 filedate 1982-12-06 generic text, type T, neo UTF8
/* LINTLIBRARY */
/*
 * efrecpckt..c
 *
 * EFTP Package
 *
 *		THIS ASSUMES NOTHING ABOUT BYTE ORDER.
 * EfRecPckt -- receive the next packet of an Eftp transfer
 * EfAbort   -- send an EFTP Abort packet
 *
 * Jeffrey Mogul @ Stanford	11-February-1981
 */

#define min(a,b)  ( (a<b)? a : b )

#include <pupconstants.h>
#include <pupstatus.h>
#include <eftp.h>

EfRecPckt(Efchan, buf, blen)
struct EftpChan *Efchan;		/* open eftp channel */
char *buf;				/* data buffer */
int   *blen;				/* number of bytes we got */
{	/* */
	int retry;
	int rstat;
	uchar rpuptype;
	ulong rpupid;
	char msgbuf[100];
	int msgbuflen;
	int dallying = 0;	/* true iff we are waiting for second EFTPEND */
	struct Port Sender;

	while (1) {	/* all exits from this loop are "return"s */
		
		rstat = pupread(&Efchan->pchan, buf, blen, &rpuptype,
				&rpupid, NULL, &Sender);

		if (rstat == BADCKSUM) continue;	/* try again */
		if (rstat == TIMEOUT) return(TIMEOUT);

		/* got a packet */

		/* we now decide if the packet is one we want.  If
		 * we are past sequence #0, it must be from out partner.
		 * Otherwise, if we are waiting to start with a specific
		 * host, it must be from that host.  If it is packet #0
		 * from a host we want, remember the host address.
		 */
		if (Efchan->sequence)	{ /* we are already running */
			if (!PortEQ(&Efchan->remport,&Sender)) {
					/* somebody trying to horn in */
					EfRecBusy(Efchan, &Sender);
					continue;
					}
			}
		else	/* not yet started */
		    if ( (Efchan->remport.host) && (Efchan->remport.net) &&
			(Efchan->remport.host != Sender.host ||
			 Efchan->remport.net != Sender.net) ) {
				/* not the sender we were awaiting */
				EfRecBusy(Efchan, &Sender);
				continue;
				}
		else
			{	/* remember this sender for future ref. */
			Efchan->remport.host = Sender.host;
			Efchan->remport.net = Sender.net;
			Efchan->remport.socket = Sender.socket;
			pupsetdest(&Efchan->pchan, &Efchan->remport);
			}

		/* packet is from our partner */
		switch ((int)rpuptype) {

		case EFTPDATA:		/* data packet */
			if (rpupid == Efchan->sequence) {  /* sequence ok */
			    EfAck(Efchan, rpupid);
			    Efchan->sequence++;
			    return(OK);
			    }
			
			if (rpupid == Efchan->sequence - 1) {
			    /* re-ack last packet */
			    EfAck(Efchan, rpupid);
			    break;	/* keep trying */
			    }
			
			if (rpupid == 0) {	/* implicit restart */
			    EfAck(Efchan, rpupid);
			    Efchan->sequence = 1;	/* restart sequence */
			    return(EFTP_RESTART);
			    }

			/* POSSIBLE BUG: if we get two copies of packet #0,
			 * is it a missed ack or a restart? Treat it as a missed
			 * ack!
			 */

			/* sender is out of synch */
			EfOutOfSynch(Efchan);
			return(EFTP_OUTOFSYNCH);

		
		case EFTPEND:		/* end of transfer */
			if (rpupid == Efchan->sequence) {  /* sequence ok */
			    if (dallying) {	/* we already saw one */
				return(EFTP_ENDOFFILE);
				}
			    else	{	/* first EFTPEnd */
				EfAck(Efchan, rpupid);
				dallying++;	/* start dally */
				pupsettimeout(&Efchan->pchan,
				    ONESEC*EFTP_DALLYWAIT); /* alter timeout */
				Efchan->sequence++;	/* bump seqeunce */
				}
			    }
			else	{	/* sender out of synch */
			    EfOutOfSynch(Efchan);
			    return(EFTP_OUTOFSYNCH);
			    }
			break;	/* gets here after first EFTPEnd */

		case EFTPABORT:
			EftpAbortCode = *(ushort *)msgbuf;
			movestring(&msgbuf[2],EftpErrMsg,msgbuflen-2);
			EftpErrMsg[msgbuflen-2] = 0; /* nullterm string */
			return(EFTP_ABORT);
		
		default:	/* we got the wrong packet type! */
			return(EFTP_ERROR);
			}
		}
	/* should never get here */
}

/*
 * EfAbort - send EFTP abort on a Pup channel
 */
EfAbort(pc, abcode, abmsg)	/* send an EFTP abort packet */
struct PupChan *pc;		/* pup channel for writing */
ushort abcode;			/* abort code */
char *abmsg;			/* abort message */
{	/* */
	char	abbuf[EFTP_MAX_PACKET];	/* for building abort message */
	int	msglen;

	msglen = strlen(abmsg);

	* ( (ushort *)&abbuf[0]) = abcode;	/* put code into buffer */
	movestring(abmsg, &abbuf[2], msglen);
		/* copy human-readable message */
	
#ifdef PUP__NNSO		/* nonstandard byte order */
	if ( (pupgetmode(pc)&PCM_WFIXLAST) && (msglen&1)) {
		/* oops! pupwrite will swap the last byte in the buffer! */
		abbuf[2+msglen++] = ' ';	/* lengthen the buffer, makes it
						 * even, then incr. msglen */ 
		}
#endif	/* */

	pupwrite(pc,EFTPABORT,0,abbuf,msglen+2);	/* send abort */
		/* !!! SHOULD WE RETURN PROPER PUPID? !!! */
}
	
EfRecBusy(efc,sndr)	/* send a Receiver Busy Abort */
struct EftpChan *efc;	/* Eftp channel to our partner, NOT to sender */
struct Port *sndr;	/* sender trying to horn in */
{	/* */
	
	/* Since the intended recipient of the abort is not the destination
	 * on our Pup channel, we must temporarily alter the PupChan
	 * to reflect this.
	 */
	pupsetdest(&efc->pchan, sndr);
	EfAbort(&efc->pchan, EFTPA_RECBUSY, 
			"Receiver busy -- another transfer in progress");
	
	/* now, restore old PupChan destination */
	pupsetdest(&efc->pchan, &efc->remport);
}

EfOutOfSynch(efc)	/* send an Out of Synch Abort */
struct EftpChan *efc;	/* Eftp channel to our partner */
{	/* */
	EfAbort(&efc->pchan, EFTPA_OUTOFSYNCH,
			"Packet received out of synch, transfer aborted");
}

EfAck(efc,seqnum)	/* Acknowledge an EFTPDATA or EFTPEND */
struct EftpChan *efc;	/* Eftp channel to our partner */
long seqnum;		/* sequence number for Ack */
{	/* */
	pupwrite(&(efc->pchan),EFTPACK,seqnum, NULL, 0);
}